-
Notifications
You must be signed in to change notification settings - Fork 273
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: adding reactive html export #1360
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
CLA Assistant Lite bot All contributors have signed the CLA ✍️ ✅ |
I have read the CLA Document and I hereby sign the CLA. |
recheck |
I like this - we should probably expose a low-level python api that isn't private (don't want to break APIs) and hopefully the smallest api (just a path?) |
or maybe we don't need the low-level api? would you still use it, if this CLI addition was added? |
I would probably still call this from the low-level api since I suspect most SSGs (e.g. Observable Framework) won't handle the html as is, and one might as-well manipulate it further with python (e.g. using BeautifulSoup as above). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is cool! We should definitely have a way to export WASM-powered HTML. Just yesterday someone asked me for this.
A few comments.
-
I tried using the CLI export on the
intro.py
tutorial and noticed that some styles were off (notebook width, codemirror editors, and KaTeX didn't render are a few things I noticed).marimo export
should look good out of the box. -
If we add a CLI, we could omit the low-level API. When integrating with Observable, you could just run the
marimo
CLI (either in a Python script usingsubprocess
, or in a shell script, etc), unless I am missing something. -
It seems odd that
cli-args
is ignored when--reactive
is passed. That sort of suggests to me that this should be its ownexport
option, egmarimo export wasm
ormarimo export reactive-html
.
If we are not prepared to do the work required for (1) yet, then we could opt for a small low-level API and revisit the CLI later ...
Thanks for the prompt response!
This uses
Sure yeah - to clarify, I'm perfectly happy calling the low-level "private" API as above (which presumably the CLI will call as-well) or, like you said, running the CLI tool and then piping the output to a different process for post-processing.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool! So Observable data loaders use require a *.html.py*
right? Or since invoking from marimo, are you using a *.html.sh
?
@dmadisetti Indeed, the simplest case would be a data-loader called #!/bin/bash
marimo export html src/data-files/intro-notebook.py --reactive --no-include-code which one can call as follow in an Observable Framework md file: ```js
const marimo_html = FileAttachment("data/marimo-intro-cli.html").html();
```
<div style="max-width:740px; margin: 0 auto;">
<div id="intro-notebook"> ${marimo_html.body} </div>
</div> Added the repo on git, if you wanted to have a look. Deployed site can be found here. |
If the data loader just goes off the shebang, I think you should be able to do #!/user/bin/env marimo export html --reactive --no-include-code
import marimo as mo
# normal app here
# ... |
@gvarnavi, given @dmadisetti's comment of using the shabang, maybe we could just do this? this would require no changes to the library and gives you a lot of flexibility in the output (b/c im sure the default html export from the CLI is not perfect) #!/user/bin/env python
from marimo import MarimoIslandGenerator
generator = MarimoIslandGenerator()
block1 = generator.add_code("import marimo as mo")
block2 = generator.add_code("mo.md('Hello, islands!')")
# Build the app
app = await generator.build()
# Render the app
output = f"""
<html>
<head>
{generator.render_head()}
</head>
<body>
{block1.render(display_output=False)}
{block2.render()}
</body>
</html>
"""
... if it's because you are coming from a python file instead of code snippets, we can add a class static method generator = MarimoIslandGenerator.from_file("path/to/file.py")
# same code |
To clarify, I don't necessarily need this PR for my purposes - I'm perfectly happy using the snippet I added in Pushed the changes I was working on before your comment @mscolnick - I think it might capture atleast some of @akshayka concerns, if you want to check it out. Regardless of the cli, a static |
I think this makes sense; islands are a little bit hidden otherwise. Regarding the limited format, I think this and normal export HTML - could be expanded to take a template, but that probably doesn't need to be added until it's needed. |
@gvarnavi , thanks for clarifying, and thanks for contributing back to us! We definitely appreciate it :) @dmadisetti, ok, good point -- wasm export is hard to find/low-level with just islands. If I understood the above discussion, it will be sufficient to just add reactive HTML export to the CLI; that will enable both gvarnavi's use case as well as let less advanced users benefit from WASM exports. If this is correct, then I support adding reactive HTML export to the CLI. @gvarnavi, I took a look and the styling does look better -- thank you. Three comments:
|
Oh yikes. # 3 might be from a work around I did to get a local cross site Web Worker. Never tested from a non-served file. This might work in islands bridge: https://gist.github.com/walfie/a80c4432bcff70fb826d5d28158e9cc4 But will probably need to tinkering. I know Myles has taken a pass at that web worker too:
|
@dmadisetti @akshayka , im pretty sure you can't run a webworker from |
(cc @gvarnavi)
Oh shoot -- I wasn't aware of that. I guess that's for security? If that's the case we might as well not include this in the CLI, and just recommend that people use @mscolnick I'll leave the decision up to you on how to proceed. |
Ah indeed, hadn't realized either since I was mostly testing directly on Observable - which is hosted. Hmm, perhaps the easiest solution then would be a static |
@gvarnavi that sounds great. i think docs could be improved for sure - i would appreciate your help, or if you have ideas, i can also incorporate them. i think snippets for users to copy to integrate into their framework of choice (e.g. Observable) go a long way since its easy to modify/adapt without creating too many permutations of options |
If the major concern is communication to users, then I think this could be mitigated with a alert dialog with something like: Caution marimo requires Web Workers to run reactively, and as such marimo islands will not work with local files. Please host this file. Because not allowing export doesn't get rid of the problem that islands won't work locally. But addressing with a notification enables this export, and documents the edgecase |
Pardon the delay, just got round to this. Added a static import asyncio
from marimo import MarimoIslandGenerator
generator = MarimoIslandGenerator.from_file("src/data-files/dislocation-fields.py")
app = asyncio.run(generator.build())
body = generator.render_body()
print(body) Note: the new Also, I've kept the cli export for now (and switched it to using the simpler static method above), until we reach a consensus on whether or not to include it. I like @dmadisetti's warning idea -- perhaps this should be implemented at the islands js file though? As in check if the file is served from a local file (perhaps using window.location.protocol or similar), and issue a warning if so? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks good! i think if we can remove exposing the CLI --reactive/--no-reactive
for now, until i can add the warning. the other additions are great and easy enough to make the CLI
with;
import os
from marimo._islands.island_generator import MarimoIslandGenerator
generator = MarimoIslandGenerator.from_file(
path.absolute_name, display_code=include_code
)
await generator.build()
html = generator.render_html()
Great, thanks for the review @mscolnick! |
force merging - looks like unrelated tests are failing on main |
🚀 Development release published. You may be able to view the changes at https://marimo.app?v=0.6.1-dev6 |
This reverts commit ba2529a.
* adding reactive_html export * doctype to avoid quirks mode * respect config width * clarified help message * islands from_file static method * switching cli export to static method * adding ; between styles * removing exposing cli option --------- Co-authored-by: Myles Scolnick <myles@marimo.io>
Big fan of the latest islands feature!
This PR extends the
_server
and_cli
export functionality to return an interactive HTML using marimo islands.CLI usage (note CLI args available in regular html export are currently ignored):
marimo export html notebook.py --reactive --no-include-code -o notebook-reactive.html
Low-level python usage (e.g. what I use to define ObservableHQ data-loaders):
Happy to include CLI tests if this looks good!